﻿using DifyToOpenAI.Common;
using DifyToOpenAI.Model;
using DifyToOpenAI.Models;
using DifyWebClient.Net.ApiClients;
using DifyWebClient.Net.Enum;
using DifyWebClient.Net.Models.Base;
using DifyWebClient.Net.Models.ChatApp;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Primitives;
using System.Net.Mime;
using System.Reactive.Linq;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading;

namespace DifyToOpenAI.Controllers
{
    [Authorize] // 需要认证的控制器或方法
    [Route("v1/chat")]
    [ApiController]
    public class ChatController : ControllerBase
    {
        private readonly ILogger<ChatController> _logger;

        public ChatController(ILogger<ChatController> logger)
        {
            _logger = logger;
        }

        [HttpPost("completions")]

        public async Task<IActionResult> CreateChatCompletion()
        {
            string ipAddress = HttpContext.Connection.RemoteIpAddress!.ToString();
            string requestLine = Request.Method + "  " + Request.GetDisplayUrl() + "  " + Request.Protocol;
            #region 获取Header数据

            IHeaderDictionary headers = Request.Headers;

            //if (headers.ContainsKey("datasource"))
            //{

            //   string datasource = headers["datasource"].ToString();

            //}
            #endregion
            #region 获取表单数据
            Dictionary<string, string> formValue = new Dictionary<string, string>();
            try
            {

                IFormCollection FormCollection = Request.Form;
                formValue = FormCollection.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.ToString());

            }
            catch (Exception)
            {
                //return Content(ex.Message, MediaTypeNames.Text.Plain, Encoding.UTF8);
            }
            #endregion
            #region 获取body数据

            string bodystring = string.Empty;
            try
            {
                using var reader = new StreamReader(Request.Body, Encoding.UTF8);
                Task<string> bodytask = reader.ReadToEndAsync();
                bodystring = bodytask.Result;


            }
            catch (Exception ex)
            {
                _logger.LogError(ex.Message);
            }


            #endregion

            /*日志*/
            StringBuilder stringBuilderlog = new StringBuilder();
            stringBuilderlog.AppendLine("");
            stringBuilderlog.AppendLine("Form IpAddress: " + ipAddress);
            stringBuilderlog.AppendLine("Request Url: " + requestLine);
            stringBuilderlog.AppendLine("Request Body: " + bodystring);
            _logger.LogInformation(stringBuilderlog.ToString());
            if (string.IsNullOrWhiteSpace(bodystring))
            {
                _logger.LogError(stringBuilderlog.ToString() + Environment.NewLine + "body is empty error");
                return BadRequest(ComServices.GetComErrorJson("body is empty error"));
            }

            //来自于客户端的openai格式请求
            ChatCompletionRequest chatCompletionRequest = new ChatCompletionRequest();
            chatCompletionRequest.RealJsonstring = bodystring;

            ModelData modelData = ComServices.FindModelById(chatCompletionRequest.model!);
            if (modelData == null || string.IsNullOrWhiteSpace(modelData.url))
            {

                _logger.LogError(stringBuilderlog.ToString() + Environment.NewLine + "model is not found");
                return BadRequest(ComServices.GetComErrorJson("model is not found"));

            }
            try
            {

                /*客户端发来的消息集合，openai接收的默认是聊天记录的集合*/
                List<ChatMessage> reqMessages = chatCompletionRequest.messages!;
               // StringBuilder difyMessageBuilder = new StringBuilder();
               // difyMessageBuilder.AppendLine(reqMessages.LastOrDefault()!.content);
                //difyMessageBuilder.AppendLine("Please answer my question based on the following historical Q&A records, using the language type of the user's questions in the historical records.");
                //string openaimessagejson = JsonSerializer.Serialize(reqMessages, ApplicationContext.jsonSerializerOptions);
                //difyMessageBuilder.AppendLine(openaimessagejson);
                string getopenaimsg = reqMessages.LastOrDefault()!.content!;
                _logger.LogInformation("openaiMessage:" + Environment.NewLine + getopenaimsg);
                /*dify对话管理器*/
                ChatAppWebClient chatAppWebClient = new ChatAppWebClient(modelData.url, modelData.key!);
                chatAppWebClient.UseUnsafeRelaxedJsonEscaping = true;
                chatAppWebClient.RequestTimeoutMilliseconds = ApplicationContext.RequestTimeoutMilliseconds;
                /*dify请求消息构造*/
                ChatMessageRequest chatMessageRequest = new ChatMessageRequest();
                chatMessageRequest.query = getopenaimsg;
                using (chatAppWebClient)
                {
                    if (string.IsNullOrWhiteSpace(chatCompletionRequest.user)) { }
                    else { chatMessageRequest.user = chatCompletionRequest.user!; }

                    /*流式还是阻塞*/
                    /*流式*/
                    if (chatCompletionRequest.stream)
                    {
                        /*流式*/
                       
                        #region SSE 模式
                        var cancellationToken = HttpContext.RequestAborted;

                        // --- 以下的 SSE 逻辑与 Minimal API 版本完全相同 ---

                        // 1. 设置 Response Header
                        HttpContext.Response.Headers.ContentType = "text/event-stream";
                        HttpContext.Response.Headers.CacheControl = "no-cache";
                        HttpContext.Response.Headers.Connection = "keep-alive";

                        try
                        {
                            chatMessageRequest.response_mode = ResponseMode.Streaming;
                            _ = chatAppWebClient.SendChatMessageAsync(chatMessageRequest);
                            foreach (SSEEventResponseBase item in chatAppWebClient.ObservChunkChatReceived)
                            {

                               // _logger?.LogInformation(item.RealJsonstring);
                                // 检查点：如果客户端已断开，就在这里抛出异常
                                cancellationToken.ThrowIfCancellationRequested();

                                /*是否输出节点信息*/
                                if (ApplicationContext.OutputNodeInfo)
                                {

                                    if (item is WorkflowStartedEventResponse) 
                                    {
                                        WorkflowStartedEventResponse workflowStartedEventResponse = (WorkflowStartedEventResponse)item;
                                       
                                        ChatCompletionChunk chatCompletionChunk = new ChatCompletionChunk(workflowStartedEventResponse.Event!+Environment.NewLine);
                                        chatCompletionChunk.id = workflowStartedEventResponse.conversation_id;
                                        await WriteSseEventAsync(chatCompletionChunk, cancellationToken);

                                    }

                                    if (item is WorkflowFinishedEventResponse)
                                    {
                                        WorkflowFinishedEventResponse workflowFinishedEventResponse = (WorkflowFinishedEventResponse)item;
                                       
                                        ChatCompletionChunk chatCompletionChunk = new ChatCompletionChunk(workflowFinishedEventResponse.Event!+ "  elapsed_time:" + workflowFinishedEventResponse.data!.elapsed_time+ Environment.NewLine);
                                        chatCompletionChunk.id = workflowFinishedEventResponse.conversation_id;
                                        await WriteSseEventAsync(chatCompletionChunk, cancellationToken);
                                    }

                                    if (item is NodeStartedEventResponse)
                                    {
                                        NodeStartedEventResponse nodeStartedEventResponse = (NodeStartedEventResponse)item;

                                        StringBuilder stringBuildermsg = new StringBuilder();
                                        stringBuildermsg.Append("NodeStarted:");
                                        stringBuildermsg.Append(nodeStartedEventResponse.data!.title+"("+ nodeStartedEventResponse.data!.node_type + ")");
                                        stringBuildermsg.Append(Environment.NewLine);
                                        string msg = stringBuildermsg.ToString();
                                        ChatCompletionChunk chatCompletionChunk = new ChatCompletionChunk(msg);
                                        chatCompletionChunk.id = nodeStartedEventResponse.conversation_id;
                                        await WriteSseEventAsync(chatCompletionChunk, cancellationToken);

                                    }
                                    if (item is NodeFinishedEventResponse)
                                    {
                                        NodeFinishedEventResponse nodeFinishedEventResponse = (NodeFinishedEventResponse)item;
                                        StringBuilder stringBuildermsg = new StringBuilder();
                                        stringBuildermsg.Append("NodeFinished:");
                                        stringBuildermsg.Append(nodeFinishedEventResponse.data!.title + "(" + nodeFinishedEventResponse.data!.node_type + ")");
                                        stringBuildermsg.Append("  "+"elapsed_time:" + nodeFinishedEventResponse.data!.elapsed_time);
                                        stringBuildermsg.Append(Environment.NewLine);

                                        string msg = stringBuildermsg.ToString() ;
                                        ChatCompletionChunk chatCompletionChunk = new ChatCompletionChunk(msg);
                                        chatCompletionChunk.id = nodeFinishedEventResponse.conversation_id;
                                        await WriteSseEventAsync(chatCompletionChunk, cancellationToken);

                                    }
                                }

                                /*difySSE断开事件,若SSE断开，则也强制断开本订阅*/
                                if (item.IsCompletedSSE)
                                {
                                    // HttpContext.Abort();
                                    await HttpContext.Response.WriteAsync("data: [DONE]\n\n", cancellationToken);// 将消息写入响应流
                                    await HttpContext.Response.Body.FlushAsync(cancellationToken); // 关键！立即将数据发送到客户端
                                    chatAppWebClient.Dispose();
                                    return new EmptyResult();
                                    //return Ok();
                                    throw new OperationCanceledException("data: [DONE]\n\n");
                                    // break;
                                }

                                /*遍历对话信息*/
                                if (item is MessageEventResponse)
                                {
                                   

                                    #region LLM输出文本块
                                    MessageEventResponse messageEventResponse = (item as MessageEventResponse)!;
                                    Console.Write(messageEventResponse!.answer!);
                                    ChatCompletionChunk chatCompletionChunk = new ChatCompletionChunk(messageEventResponse!.answer!);
                                    chatCompletionChunk.id = messageEventResponse.conversation_id;
                                    await WriteSseEventAsync(chatCompletionChunk, cancellationToken);
                                    #endregion
                                }


                                /*dify结束事件*/
                                if (item is MessageEndEventResponse)
                                {
                                    MessageEndEventResponse messageEventResponse = (item as MessageEndEventResponse)!;
                                    ChatCompletionChunk chatCompletionChunk = new ChatCompletionChunk();
                                    chatCompletionChunk.id = messageEventResponse.conversation_id;
                                    chatCompletionChunk.choices = new List<ChoiceChunk>();
                                    ChoiceChunk choiceChunk = new ChoiceChunk() { finish_reason= "stop" };
                                    chatCompletionChunk.choices.Add(choiceChunk);
                                    await WriteSseEventAsync(chatCompletionChunk, cancellationToken);
                                    await HttpContext.Response.WriteAsync("data: [DONE]\n\n", cancellationToken);// 将消息写入响应流
                                    await HttpContext.Response.Body.FlushAsync(cancellationToken); // 关键！立即将数据发送到客户端
                                    chatAppWebClient.Dispose();
                                    return new EmptyResult();
                                    throw new OperationCanceledException("data: [DONE]\n\n");

                                }
                            }

                        }
                       
                        catch (Exception ex)
                        {
                            // 处理其他可能的异常
                            //   Console.WriteLine($"发生错误 (Controller): {ex.Message}");
                            _logger.LogWarning(ex.Message);
                        }
                        #endregion
                        return new EmptyResult();
                    }
                    /*阻塞模式*/
                    else
                    {
                       
                        chatMessageRequest.response_mode = ResponseMode.Blocking;
                        /*获取dify的返回消息*/
                        ChatCompletionResponse chatCompletionResponse = chatAppWebClient.SendChatMessage(chatMessageRequest);
                        #region openai常规阻塞模式返回
                        /*标准的openai返回的ChatCompletion*/
                        ChatCompletion chatCompletion = new ChatCompletion(chatCompletionResponse.answer!);
                        chatCompletion.id = chatMessageRequest.conversation_id;
                        chatCompletion.usage = new Models.Usage();
                        try
                        {
                            chatCompletion.usage.prompt_tokens = Convert.ToInt32(chatCompletionResponse.metadata!.usage.prompt_tokens);
                            chatCompletion.usage.completion_tokens= Convert.ToInt32(chatCompletionResponse.metadata!.usage.completion_tokens);
                            chatCompletion.usage.total_tokens = Convert.ToInt32(chatCompletionResponse.metadata!.usage.total_tokens);
                        }
                        catch (Exception)
                        {

                           // throw;
                        }
                        string json = JsonSerializer.Serialize(chatCompletion, ApplicationContext.jsonSerializerOptions);
                        ContentResult resContent = Content(json.ToString()!, MediaTypeNames.Application.Json, Encoding.UTF8);
                        resContent.StatusCode = 200;
                        _logger.LogInformation("Response StatusCode: " + resContent.StatusCode);
                        _logger.LogInformation("Response Body: " + Environment.NewLine + resContent.Content);


                        return resContent;

                        #endregion
                    }

                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex.Message);
                return BadRequest(ComServices.GetComErrorJson(ex.Message));
                // throw;
            }


        }

        private async Task WriteSseEventAsync<T>(T data, CancellationToken cancellationToken)
        {
            // SSE 格式要求数据以 "data: " 开头，并以两个换行符 "\n\n" 结尾
            JsonSerializerOptions jsonSerializerOptions = new JsonSerializerOptions() { };
            jsonSerializerOptions.Encoder = ApplicationContext.jsonSerializerOptions.Encoder;
            jsonSerializerOptions.WriteIndented = false;/*SSE必须一整行*/
            var json = JsonSerializer.Serialize(data, jsonSerializerOptions);
            var sseFormattedMessage = $"data: {json}\n\n";
           // _logger.LogInformation(sseFormattedMessage); /*记录sse返回的日志*/
            await HttpContext.Response.WriteAsync(sseFormattedMessage, cancellationToken);// 将消息写入响应流
            await HttpContext.Response.Body.FlushAsync(cancellationToken); // 关键！立即将数据发送到客户端
        }

    }


}

